<template>
  <div class="app-container">
    <el-row :gutter="20">
      <el-col :span="11">
        <h3>设备报警</h3>
        <Alarm :info="terminalParams.alarm" />
        <h3>坐标校准</h3>
        <div class="left-table" :style="{ height: tableHeight + 'px' }">
          <div class="flex-head">
            <el-form :model="queryParams" size="small" inline>
              <div class="flex-row">
                <div>
                  <el-form-item label="模式" prop="mode">
                    <el-select
                      v-model="queryParams.mode"
                      placeholder=""
                      style="width: 80px"
                      @change="getList"
                    >
                      <el-option
                        v-for="item in modeList"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value"
                      />
                    </el-select>
                  </el-form-item>
                  <el-form-item label="校准位置" prop="face">
                    <el-select
                      v-model="queryParams.face"
                      placeholder=""
                      style="width: 80px"
                      @change="getList"
                    >
                      <el-option
                        v-for="item in faceList"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value"
                      />
                    </el-select>
                  </el-form-item>
                </div>
                <div>
                  <el-button size="mini" type="danger" @click="clearCoordinate">
                    清空坐标
                  </el-button>
                  <el-button size="mini" type="warning" @click="getList">
                    重置坐标
                  </el-button>
                  <el-button size="mini" type="success" @click="saveCoordinate">
                    保存坐标
                  </el-button>
                </div>
              </div>
            </el-form>
          </div>
          <div v-for="(list, k) in dataList" :key="k" class="flex-row">
            <Online-table
              :data="list"
              :index="k"
              :mode="queryParams.mode"
              :info="terminalParams"
              :form="editForm"
              :disabled="isDisable"
              @change="changeCoordinate"
              @position="changePosition"
              @lock="changeLock"
            />
          </div>
        </div>
      </el-col>
      <el-col :span="13">
        <h3>客户端命令</h3>
        <div>
          <el-button
            type="warning"
            :disabled="configParams.lockStatus == 1"
            size="small"
            @click="changeStatus"
          >
            解锁客户端
          </el-button>
          <el-button type="primary" size="small" @click="restartClient">
            重启客户端
          </el-button>
          <el-button type="primary" size="small" @click="getConfig"> 刷新配置 </el-button>
          <el-button type="primary" size="small" @click="heartbeatTest">
            心跳检测
          </el-button>
          <el-button
            type="primary"
            size="small"
            :disabled="isDisable"
            @click="unloadMedicine"
          >
            执行卸货
          </el-button>
          <el-button type="success" size="small" @click="saveConfig">保存配置</el-button>
          <el-button type="warning" size="small" :disabled="isDisable" @click="supply"
            >收回机械臂</el-button
          >
        </div>
        <el-row :gutter="20">
          <el-col :span="8">
            <h3>控制面板</h3>
            <Direction
              :cabinet-id="queryParams.cabinetId"
              :ws-id="timeStamp"
              :face="queryParams.face"
              :info="terminalParams"
              :form="editForm"
              :disabled="isDisable"
              @changeForm="changeForm"
              @changeDisable="changeDisable"
              @saveShipment="saveShipment"
            />
          </el-col>
          <el-col :span="16">
            <el-row :gutter="20">
              <h3>状态摘要</h3>
              <Status-panel :info="configParams" :plc-info="terminalParams" />
              <h3>基本配置</h3>
              <Base-config
                :cabinet-id="queryParams.cabinetId"
                :form="editForm"
                :com-list="terminalParams.serialPortList || []"
                @changeForm="changeForm"
                @useYaxisUp="useYaxisUp"
              />
            </el-row>
          </el-col>
        </el-row>
      </el-col>
    </el-row>
  </div>
</template>

<script>
import {
  listOnlineSlot,
  getOnlineConfig,
  saveOnlineSlot,
  updateOnlineStatus,
  restartOnline,
  getOnlineInfo,
  onlineHeartbeat,
  onlineUnload,
  onlineMoveByCoordinate,
  onlineLockSlot,
  onlineSaveParam,
  onlineRetract,
} from "@/api/mc/cabinet";
import OnlineTable from "./components/OnlineTable.vue";
import Alarm from "./components/Alarm.vue";
import Direction from "./components/Direction.vue";
import StatusPanel from "./components/StatusPanel.vue";
import BaseConfig from "./components/BaseConfig.vue";
export default {
  name: "online-control",
  components: { OnlineTable, Alarm, Direction, StatusPanel, BaseConfig },
  data() {
    return {
      queryParams: {
        face: 1,
        mode: 1,
        cabinetId: "",
      },
      dataList: [],
      modeList: [
        { label: "自动", value: 1 },
        { label: "手动", value: 2 },
      ],
      faceList: [
        { label: "正面", value: 1 },
        { label: "反面", value: 3 },
      ],
      terminalParams: {
        serialPortList: [], // 串口列表
      }, // 终端参数
      configParams: {}, // 柜机参数
      editForm: {
        // 配置表单
        cabinetId: "",
        shipmentXAxis: "",
        shipmentYAxis: "",
        maxXAxis: "",
        maxYAxis: "",
        zaxis: "",
        com: "",
        baudRate: "",
        dataBits: "",
        checkBit: "",
        stopBit: "",
        readTimeout: "",
        writeTimeout: "",
        speed: "",
        yaxisUp: "",
        sensorCom: "",
      },
      socket: null, // socket
      timeStamp: 0, // 时间戳
      isConnect: false, // 是否连接
      timer: null, // 定时器
      delay: 0, // 延迟时间
      tableHeight: 0, // 表格高度
      isDisable: false, // 是否禁用
      realTimer: null, // 实时数据定时器
    };
  },
  created() {
    this.timeStamp = new Date().getTime();
    this.tableHeight = window.innerHeight - 320;
    this.createWebSocket();
    this.queryParams.cabinetId = this.$route.query.id;
    this.editForm.cabinetId = this.$route.query.id;
    this.getList();
    this.getConfig();
  },
  methods: {
    /** 查询出药记录列表 */
    getList() {
      listOnlineSlot(this.queryParams).then((res) => {
        this.dataList = res.data;
      });
    },
    // 获取配置信息
    getConfig() {
      getOnlineConfig(this.queryParams.cabinetId).then((res) => {
        this.configParams = res.data;
        if (res.data.cabinetParam) {
          this.editForm = res.data.cabinetParam;
          this.$modal.msgSuccess("获取配置信息成功");
        }
      });
    },
    // 告知终端通过websocket返回信息
    getTerminalInfo() {
      this.delay = new Date().getTime();
      getOnlineInfo({
        cabinetId: this.queryParams.cabinetId,
        wsId: this.timeStamp,
      });
    },
    // 清空坐标位置
    clearCoordinate() {
      this.dataList.forEach((item) => {
        item.forEach((i) => {
          i.xaxis = -1;
          i.yaxis = -1;
          i.zaxis = -1;
          i.yaxisUp = -1;
        });
      });
    },
    // 改变坐标位置
    changeCoordinate({ index, data }) {
      this.dataList[index] = data;
    },
    // 保存坐标位置
    saveCoordinate() {
      let data = {
        ...this.queryParams,
        list: this.dataList,
      };
      saveOnlineSlot(data).then((res) => {
        this.$modal.msgSuccess("保存成功");
        this.calculateDelay();
      });
    },
    // 改变状态
    changeStatus() {
      this.$confirm("解除绑定后，客户端将无法进行取药操作，是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.delay = new Date().getTime();
          updateOnlineStatus({ cabinetId: this.queryParams.cabinetId }).then((res) => {
            this.configParams.lockStatus = 1;
            this.calculateDelay();
          });
        })
        .catch(() => {});
    },
    // 重启客户端
    restartClient() {
      this.delay = new Date().getTime();
      restartOnline({ cabinetId: this.queryParams.cabinetId }).then((res) => {
        this.calculateDelay();
      });
    },
    // 心跳测试
    heartbeatTest() {
      this.delay = new Date().getTime();
      onlineHeartbeat({ cabinetId: this.queryParams.cabinetId }).then((res) => {
        this.calculateDelay();
      });
    },
    // 执行卸货
    unloadMedicine() {
      if (this.terminalParams.serialPortList.length == 0) {
        this.$modal.msgError("请先连接串口");
        return;
      }
      this.changeDisable(true);
      this.delay = new Date().getTime();
      onlineUnload({ cabinetId: this.queryParams.cabinetId }).then((res) => {
        this.calculateDelay();
      });
    },
    // 计算延迟
    calculateDelay() {
      let now = new Date().getTime();
      this.terminalParams["delay"] = Math.abs(now - this.delay);
      this.$forceUpdate();
    },
    // 修改数据
    changeForm(val) {
      this.editForm[val.field] = val.value;
    },
    // 使用Y轴抬升偏移量
    useYaxisUp(val) {
      this.dataList.forEach((item) => {
        item.forEach((i) => {
          if (i.yaxisUp == -1) {
            i.yaxisUp = val;
          }
        });
      });
    },
    // 保存下药点坐标
    saveShipment() {
      this.sendSave({
        eventType: "EDIT_EXPORT",
        shipmentXAxis: this.editForm.shipmentXAxis,
        shipmentYAxis: this.editForm.shipmentYAxis,
      });
      this.$modal.msgSuccess("操作成功");
    },
    // 移动到指定位置
    changePosition({ index, data }) {
      this.changeDisable(true);
      onlineMoveByCoordinate({
        cabinetId: this.queryParams.cabinetId,
        xaxis: data.xaxis,
        yaxis: data.yaxis,
        zaxis: data.zaxis,
      }).then((res) => {
        this.calculateDelay();
      });
    },
    // 锁槽
    changeLock(val) {
      onlineLockSlot({
        cabinetId: this.queryParams.cabinetId,
        face: this.queryParams.face,
        mode: this.queryParams.mode,
        ...val.data,
      }).then((res) => {
        if (this.queryParams.mode == 1) {
          this.dataList = res.data;
        } else {
          this.getList();
        }
        this.$modal.msgSuccess("操作成功");
      });
    },
    // 保存参数配置
    saveConfig() {
      onlineSaveParam({
        cabinetId: this.queryParams.cabinetId,
        cabinetParam: this.editForm,
        wsId: this.timeStamp,
      }).then((res) => {
        this.$modal.msgSuccess("保存成功");
      });
    },
    // 补药操作
    supply() {
      if (this.terminalParams.serialPortList.length == 0) {
        this.$modal.msgError("请先连接串口");
        return;
      }
      this.changeDisable(true);
      this.delay = new Date().getTime();
      onlineRetract({ cabinetId: this.queryParams.cabinetId }).then((res) => {
        this.calculateDelay();
      });
    },
    // 设置禁用
    changeDisable(val) {
      this.isDisable = val;
    },
    // 发送修改内容
    sendSave(data) {
      let content = {
        eventType: "COMMON",
        wsId: this.configParams.serialNumber,
        data: data,
      };
      this.socket.send(JSON.stringify(content));
    },
    // 初始化WebSocket连接
    createWebSocket() {
      let that = this;
      try {
        that.socket = new WebSocket(process.env.VUE_APP_SOCKET_URL + this.timeStamp);
        that.initWebSocket();
      } catch (e) {
        that.reConnect(); // 重连
      }
    },
    // 初始化WebSocket事件监听
    initWebSocket() {
      // 监听WebSocket连接打开事件
      this.socket.onopen = () => {
        console.log("WebSocket连接已打开", this.socket);
        this.isConnect = true; // 更新连接状态

        this.realTimer && clearInterval(this.realTimer);
        this.getTerminalInfo();
        this.realTimer = setInterval(() => {
          this.getTerminalInfo();
        }, 2000);
      };
      // 监听WebSocket连接关闭事件
      this.socket.onclose = () => {
        console.log("WebSocket连接已关闭", this.socket);
        this.isConnect = false; // 更新连接状态
        this.reConnect(); // 重连
      };

      // 监听WebSocket消息接收事件
      this.socket.onmessage = (event) => {
        let data = JSON.parse(event.data);
        switch (data.type) {
          case "REAL_TIME_INFORMATION":
            this.delay = data.delay;
            this.terminalParams = data;
            this.calculateDelay();
            break;
          case "WARN":
            this.$modal.msgError(data.message);
            break;
          case "SUCCESS":
            this.$modal.msgSuccess(data.message);
            break;
          case "COMPLETE":
            // 执行完成
            this.changeDisable(false);
            break;
        }
      };

      // 监听WebSocket错误事件
      this.socket.onerror = (error) => {
        console.error("WebSocket发生错误:", error);
        this.isConnect = false; // 更新连接状态
        this.reConnect(); // 重连
      };
    },
    // 重连
    reConnect() {
      if (this.isConnect) return;
      if (this.realTimer) {
        clearInterval(this.realTimer);
        this.realTimer = null;
      }
      if (this.socket) {
        if (this.timer) clearTimeout(this.timer);
        this.timer = setTimeout(() => {
          this.createWebSocket();
        }, 5000);
      }
    },
  },
  destroyed() {
    if (this.socket) {
      this.socket.close();
      this.socket = null;
    }
    // 清除实时定时器
    if (this.realTimer) {
      clearInterval(this.realTimer);
      this.realTimer = null;
    }
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
  },
};
</script>
<style lang="scss" scoped>
.left-table {
  border: 1px solid #72b5f8;
  box-shadow: inset 0 0 10px rgba(64, 160, 255, 0.2);
  border-radius: 10px;
  overflow-y: auto;
  .flex-head {
    position: sticky;
    top: 0;
    z-index: 8;
    background-color: #fff;
  }
}
.flex-row {
  display: flex;
  align-items: center;
  padding: 10px;
  justify-content: space-between;
  border-bottom: 1px solid #ccc;
}
.disabled-value {
  width: 100%;
  height: 32px;
  display: inline-block;
  padding: 0 15px;
  border-radius: 4px;
  border: 1px solid #dcdfe6;
  background-color: #f9f9f9;
  border-color: #dfe4ed;
  color: #c0c4cc;
}
::v-deep .el-form-item {
  margin-bottom: 0;
}
::v-deep .el-form-item__label {
  padding: 0;
}
</style>
